﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace Framework.Data
{
    /// <summary>
    /// 原来老系统的数据库连接串加密解密工具类。
    /// </summary>
    internal static class ConnectionStringCipher
    {
        private const string CipherKey = "{5A128714-221B-4187-99D0-73E32A397325}";

        /// <summary>
        /// 加密连接字符串
        /// </summary>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        internal static string EncryptCipher(string connectionString)
        {
            byte[] data = connectionString.ToCharArray().Select(Convert.ToByte).ToArray();

            var aes = Aes.Create();
            var cache = new MemoryStream();

            byte[] key = GetCryptographyKey();

            var stream = new CryptoStream(cache,
                aes.CreateEncryptor(key, GetIVByKey(key)),
                CryptoStreamMode.Write);

            stream.Write(data, 0, data.Length);
            stream.FlushFinalBlock();

            return BuildToken(cache.ToArray());
        }

        /// <summary>
        /// 解密连接字符串
        /// </summary>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        internal static string DecryptCipher(string connectionString)
        {
            var ms = new MemoryStream();
            var charArray = connectionString.ToCharArray();
            var sb = new StringBuilder();

            for (var i = 0; i < charArray.Length; i++)
            {
                sb.Append(charArray[i]);

                if (i % 2 == 1)
                {
                    ms.WriteByte(Convert.ToByte(sb.ToString(), 16));
                    sb.Remove(0, sb.Length);
                }
            }

            var data = ms.ToArray();

            var aes = Aes.Create();
            var cache = new MemoryStream();
            var key = GetCryptographyKey();

            var stream = new CryptoStream(cache,
                aes.CreateDecryptor(key, GetIVByKey(key)),
                CryptoStreamMode.Write);

            stream.Write(data, 0, data.Length);
            stream.FlushFinalBlock();

            var result = new string(cache.ToArray().Select(Convert.ToChar).ToArray());
            return result;
        }

        private static byte[] GetCryptographyKey()
        {
            SHA256 sha = SHA256.Create();
            return sha.ComputeHash(Encoding.UTF8.GetBytes(CipherKey));
        }

        private static string BuildToken(byte[] data)
        {
            var sb = new StringBuilder();

            foreach (byte b in data)
            {
                sb.AppendFormat("{0:X2}", b);
            }

            string result = sb.ToString();
            return result;
        }

        private static byte[] GetIVByKey(byte[] key)
        {
            byte[] iv = new byte[key.Length / 2];
            Array.Copy(key, iv, iv.Length);

            return iv;
        }
    }
}
